package initialization

import (
	"encoding/json"
	"examProject/intelnal/router"
	"examProject/intelnal/tools/consul"
	"examProject/pkg/config"
	golbal2 "examProject/pkg/golbal"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func init() {
	// 读取配置
	InitConfig()
	//注册consul
	//配置日志
	InitZap()
	// 加载路由
	InitRouter()
	//初始化grpc连接
	InitGrpcDail()
}

func InitGrpcDail() {
	// 因为客户端要在注册中心中与服务端建立连接 那么客户端和服务端必须都存在注册中心中
	// 如果服务端在注册中心中未进行注册  那么客户端肯定连接不到
	// 所以要先判断服务端是否已经注册到注册中心
	// 如果服务端已经存在注册中心，那么客户端连接服务端的时候，可以直接从注册中心获取服务端的连接信息
	// 如果服务端未注册到注册中心，返回提示语，服务端未进行注册
	//客户端注册注册中心，如果发现服务端未进行注册，则可以在客户端将服务端注册到注册中心  那么服务端就不用再次注册

	//注册
	//注销
	//获取所有服务列表
	//服务过滤

	consulClient := consul.NewConsulClient(golbal2.ApiConfig.Consul.Host, golbal2.ApiConfig.Consul.Port)
	////客户端注册前查询是否已经存在该服务--使用过滤表达式	//一定要判断空指针
	result := consulClient.ServicesWithFilter(fmt.Sprintf(`Service == "%s"`, golbal2.ApiConfig.Server.Name))
	if len(result) == 0 {
		// 注册到 consul
		consulClient.Register(golbal2.ApiConfig.Server.Host, golbal2.ApiConfig.Server.Port, golbal2.ApiConfig.Server.Name, golbal2.ApiConfig.Server.Tags, uuid.NewString())
	} else {
		zap.S().Infof(fmt.Sprintf("%s:already registered to consul", golbal2.ApiConfig.Server.Name))
	}

	//rpc consul服务
	rpcServerIp := ""
	rpcServerPort := 0
	srvResult := consulClient.ServicesWithFilter(fmt.Sprintf(`Service == "%s"`, golbal2.ApiConfig.Server.RpcName))
	if len(srvResult) > 0 {
		for _, value := range srvResult {
			rpcServerIp = value.Address
			rpcServerPort = value.Port
			break
		}
	} else {
		zap.S().Infof(fmt.Sprintf("%s:not found,Please register server into consul", golbal2.ApiConfig.Server.RpcName))
		return
	}

	//1. 建立和server端的 grpc连接   8888用户服务端口
	conn, err := grpc.Dial(fmt.Sprintf("%s:%d", rpcServerIp, rpcServerPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
	zap.S().Infow("rpc server connected:::", conn)
	if err != nil {
		zap.S().Infow("grpc connection error: ", err)
	}
	// 2. 将api端的服务注册到grpc中  proto中生成协议服务

}

func InitConfig() {
	//1. 先用viper读取本地yaml文件配置->拿到nacos的配置项
	//初始化
	v := viper.New()
	//设置配置文件
	v.SetConfigFile("/Users/fuyx/GolandProjects/examProject/application-dev.yaml")
	if err := v.ReadInConfig(); err != nil {
		zap.S().Infow("yaml file read error:", err)
		return
	}
	//1.1 把nacos的配置写成全局变量 -> 只是为了方便下面的程序调用 （可以写成全局变量，也可以直接使用结构题调用）
	golbal2.NacosConfig = &config.Nacos{}
	//读取的时候层级关系对应
	if err := v.Unmarshal(golbal2.NacosConfig); err != nil {
		zap.S().Infow("nacos config unmarshal error:", err)
		return
	}

	//2. 开始从nacos获取项目配置
	//2.1 创建clientConfig   -- 开启鉴权的情况下 需要加上user和password  （配置nacos的基础属性）
	clientConfig := constant.ClientConfig{
		NamespaceId:         golbal2.NacosConfig.NamespaceId, // 命名空间
		TimeoutMs:           5000,                            // 超时时间
		NotLoadCacheAtStart: true,                            //是否开启缓存
		LogDir:              "tmp/nacos/log",                 //本地的nacos日志记录
		CacheDir:            "tmp/nacos/cache",               //本地nacos的执行缓存
		LogLevel:            "debug",                         //日志级别
		Username:            golbal2.NacosConfig.UserName,    //开启鉴权 -- userName
		Password:            golbal2.NacosConfig.Password,
	}
	//2.2至少一个ServerConfig  nocs的服务配置
	serverConfigs := []constant.ServerConfig{
		{
			IpAddr: golbal2.NacosConfig.IpAddr,       //nacos服务器的IP地址 （也可以是域名）
			Port:   uint64(golbal2.NacosConfig.Port), //nacos服务器的端口号
		},
	}

	//2.3创建动态配置客户端   根据上面的配置来创建naco的连接
	configClient, _ := clients.CreateConfigClient(map[string]interface{}{
		"serverConfigs": serverConfigs,
		"clientConfig":  clientConfig,
	})
	//2.4配置要读取的nacos中的group和dataId    确定你要读取的配置
	content, err := configClient.GetConfig(vo.ConfigParam{
		DataId: golbal2.NacosConfig.DataId,
		Group:  golbal2.NacosConfig.Group})
	if err != nil {
		zap.S().Infow("GerNacosConfig Error:::", err)
		return
	}
	//2.5初始化全局变量
	golbal2.ApiConfig = &config.ApiConfig{}
	//json 反序列化的时候读取的是json的配置  在结构体中需要配置 json属性
	err = json.Unmarshal([]byte(content), golbal2.ApiConfig)
	if err != nil {
		zap.S().Infow("Json Unmarshal Error:::", err)
		return
	}
	//
	//var aliPayErr error
	//if golbal.AliPayClient, err = alipay.New(golbal2.ApiConfig.AliPay.KAppId, golbal2.ApiConfig.AliPay.KPrivateKey, false); aliPayErr != nil {
	//	zap.S().Infow("load aliPay Error::", aliPayErr)
	//	return
	//}
	//
	////公钥模式
	//publicKeyErr := golbal.AliPayClient.LoadAliPayPublicKey(golbal2.ApiConfig.AliPay.KPublicKey)
	//if publicKeyErr != nil {
	//	zap.S().Infow("load publicKey Error::", publicKeyErr)
	//	return
	//}
}

func InitZap() {
	//全局替换  使zap包在全局生效
	zapConfig := zap.NewDevelopmentConfig()
	zapConfig.OutputPaths = []string{
		"/Users/fuyx/GolandProjects/examProject/myproject.log",
	}
	//构建 之后配置才生效
	logger, _ := zapConfig.Build()
	zap.ReplaceGlobals(logger)

	//
	//config := zap.NewDevelopmentConfig()
	//config.OutputPaths = []string{
	//	golbal.ApiConfig.Log.LogPath,
	//	"stdout",
	//}
	//logger, _ := config.Build()
	////全局变量配置
	//zap.ReplaceGlobals(logger)
}

func InitRouter() {
	//初始化gin
	router := gin.Default()
	//加载路由组
	routerGroup.RouterGroup(router)
	//全局变量赋值
	golbal2.Router = router
}
